package com.src.xyzk_personal.EOL;

public class DesVinToPin {
	private static String TAG = "DesVinToPin";
	public static String JAC_KEY = "11111001";
	public static String ZOTYE_KEY="11111002";
	public static String HCXY_KEY = "11111003";

	//常量
	private final static int KEYWORDNUM = 8;
	private final static int ORNUMBER0 = 0x8A;
	private final static int ORNUMBER1 = 0x5D;
	private final static int ORNUMBER2 = 0xF1;
	private final static int ORNUMBER3 = 0x33;
	private final static int ORNUMBER4 = 0x24;
	private final static int ORNUMBER5 = 0xA1;
	private final static int ORNUMBER6 = 0x20;
	private final static int ORNUMBER7 = 0x22;
	private final static int ENCODETIMES = 10;
	private final static String KEYNAME = "Dias_Key";
	private final static int DESNUM = 8;

	private boolean Is3DES;// 3次DES标志
	private byte[] SubKey = new byte[32 * 48];
	private byte[] deskey = new byte[16];
	private byte[] Tmp = new byte[256];
	private byte[] m_KeyWord = {(byte) ORNUMBER0,ORNUMBER1,(byte) ORNUMBER2,ORNUMBER3,ORNUMBER4,(byte) ORNUMBER5,ORNUMBER6,ORNUMBER7};
	private byte[] IP_Table = {
			58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
			62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
			57, 49, 41, 33, 25, 17,  9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
			61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
	};
	private byte[] IPR_Table = {
			40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
			38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
			36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
			34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41,  9, 49, 17, 57, 25
	};
	private byte[] E_Table = {
			32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,
			8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
			16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
			24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1
	};
	private byte[] P_Table = {
			16, 7, 20, 21, 29, 12, 28, 17, 1,  15, 23, 26, 5,  18, 31, 10,
			2,  8, 24, 14, 32, 27, 3,  9,  19, 13, 30, 6,  22, 11, 4,  25
	};
	private byte[] PC1_Table = {
			57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
			10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
			63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
			14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
	};
	private byte[] PC2_Table = {
			14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
			23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
			41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
			44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
	};
	private byte[] LOOP_Table = {
			1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
	};
	//8 * 4* 16
	private byte[] S_Box = {
			// S1
			14,4,	13,	 1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
			0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
			4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
			15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,
			// S2
			15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
			3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
			0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
			13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,
			// S3
			10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
			13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
			13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
			1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,
			// S4
			7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
			13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
			10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
			3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,
			// S5
			2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
			14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
			4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
			11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,
			// S6
			12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
			10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
			9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
			4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,
			// S7
			4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
			13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
			1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
			6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,
			// S8
			13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
			1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
			7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
			2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
	};
	private String m_key = null;	//密钥算子
	//	class PSubKey
//	{
//		public byte[] subkey = new byte[16*48];
//	}
	//众泰DES算法
	public void GererateZotyePin(String Vin,byte [] Pin)
	{
		byte[] Pincode = new byte[8];
		GeneratePin(Vin, Pincode, ZOTYE_KEY);
		for(int i = 0; i < 4; i ++)
			Pin[i] = Pincode[i * 2];
	}
	public void CreateHCXYPin(String Vin, byte [] Pin)
	{
		byte[] Pincode = new byte[8];
		GeneratePin(Vin, Pincode, ZOTYE_KEY);
		for(int i = 0; i < 4; i ++)
			Pin[i] = Pincode[i];
	}
	//计算江淮PIN码
	public void GenerateJacPin(String Vin,byte[] Pin)
	{
		byte[] Pincode = new byte[8];
		GeneratePin(Vin, Pincode, JAC_KEY);
		//for(int i = 0; i < 4; i ++)
		//	Pin[i] = Pincode[i * 2];
		Pin[0] = (byte) 0xAA;
		Pin[1] = (byte) 0xBB;
		Pin[2] = (byte) 0xCC;
		Pin[3] = (byte) 0xDD;
	}
	//根据VIN计算出PIN码
	private boolean GeneratePin(String Vin,byte [] Pin,String Key)
	{
		//判断VIN长度
		if( Vin == null || Vin.length() != 17)  return false;
		//判断KEY
		if(Key == null || Key.length() != 8) return false;
		//取VIN码后面8位
		byte [] vintrip = new byte[8];
		System.arraycopy( Vin.getBytes(), 9,vintrip, 0, 8);
		//输出PIN码
		if(Pin.length < 4) return false;
		byte[] v_pin = new byte[8];
		Des_Go(v_pin, vintrip, vintrip.length, Key, false);
		for(int i = 0; i < 8; i ++)
			Pin[i] = v_pin[i];
		return true;
	}
	//DES
	boolean Des_Go(byte[] Pout,byte[] Pin,long datalen,String Key,boolean Type)
	{
		if(Pout == null || Pin == null || Key == null) return false;
		if(((datalen+7) & 0xfffffff8) == 0) return false;
		SetKey(Key.getBytes(), Key.length());
		int outPos = 0;
		int inPos = 0;
		if(!Is3DES)
		{
			// 1次DES
			long j = datalen >> 3;
			for(long i = 0; i < j; i ++)
			{
				DES(Pout, outPos, Pin, inPos, SubKey, 0, Type);
				outPos += DESNUM;
				inPos += DESNUM;
			}
		}
		else
		{
			// 3次DES 加密:加(key0)-解(key1)-加(key0) 解密::解(key0)-加(key1)-解(key0)
			long j = datalen >> 3;
			for(long i = 0; i < j; i ++)
			{
				DES(Pout, outPos, Pin, inPos, SubKey, 0, Type);
				DES(Pout, outPos, Pin, inPos, SubKey, 16*48, !Type);
				DES(Pout, outPos, Pin, inPos, SubKey, 0, Type);
				outPos += DESNUM;
				inPos += DESNUM;
			}
		}
		return true;
	}
	void SetKey(byte[] key,int len)
	{
		deskey.clone();
		System.arraycopy(key, 0, deskey, 0, len > 16?16:len);
		SetSubKey(SubKey,0, deskey,0);
		if(len > 8)
		{
			SetSubKey(SubKey,16*48,deskey,8);
			Is3DES = true;
		}
		else
			Is3DES = false;
	}
	void DES(byte[] Pout,int outPos,byte[] Pin,int PinPos,byte[] Psubkey,int subkeyPos,boolean type)
	{
		byte[] M = new byte[64];
		byte[] tmp = new byte[32];
		//Li = M[0]   Ri = M[32]
		ByteToBit(M, 0, Pin, PinPos, 64);
		Transform(M, 0, M, 0, IP_Table, 64);
		if(type == false)
		{
			for(int i = 0; i < 16; i ++)
			{
				System.arraycopy(M, 32, tmp, 0, 32);
				F_func(M, 32,Psubkey,subkeyPos + i*48);
				Xor(M, 32, M, 0, 32);
				System.arraycopy(tmp, 0, M, 0, 32);
			}
		}
		else
		{
			for(int i = 15; i >= 0; i --)
			{
				System.arraycopy(M, 0, tmp, 0, 32);
				F_func(M, 0,Psubkey,subkeyPos + i);
				Xor(M, 0, M, 32, 32);
				System.arraycopy(tmp, 0, M, 32, 32);
			}
		}
		Transform(M, 0, M, 0, IPR_Table, 64);
		BitToByte(Pout, outPos, M, 0, 64);
	}
	void SetSubKey(byte[] Pkey,int PkeyPos,byte[] Key,int keyPos)
	{
		byte[] K = new byte[64];
		//KL  --k[0]  ; KR = k[28]
		ByteToBit(K, 0, Key, keyPos, 64);
		Transform(K,0, K,0, PC1_Table, 56);
		for(int i = 0; i < 16; i ++)
		{
			RotateL(K, 0 , 28, LOOP_Table[i]);
			RotateL(K, 28, 28, LOOP_Table[i]);
			Transform(Pkey,PkeyPos + i * 48, K,0, PC2_Table, 48);
		}
	}
	void F_func(byte[] Pin,int PinPos,byte[] Pki,int PkiPos)
	{
		byte[] MR = new byte[48];
		Transform(MR,0, Pin, PinPos,E_Table, 48);
		Xor(MR,0,Pki,PkiPos,48);
		S_func(Pin,PinPos, MR,0);
		Transform(Pin,PinPos,Pin, PinPos,P_Table,32);
	}
	void S_func(byte[] Pout,int PoutPos,byte[] Pin,int PinPos)
	{
		byte j,k;
		int InAdd = PinPos;
		int OutAdd = PoutPos;
		for(int i = 0; i < 8; i ++)
		{
			j = (byte) ((Pin[InAdd + 0] << 1) + Pin[InAdd + 5]);
			k = (byte) ((Pin[InAdd + 1] << 3) + (Pin[InAdd + 2] << 2) + (Pin[InAdd + 3] << 1) +  + Pin[InAdd + 4]);
			ByteToBit(Pout,OutAdd,S_Box,i*64 +j*16 + k,4);
			InAdd += 6;
			OutAdd += 4;
		}
	}
	void Transform(byte[] Pout,int Pstart,byte[] Pin,int PinPos,byte[] Table,int Plen)
	{
		for(int i = 0; i < Plen; i ++)
			Tmp[i] = (byte)Pin[PinPos + (Table[i] & 0xFF) - 1];
		System.arraycopy(Tmp, 0, Pout, Pstart, Plen);
	}
	void Xor(byte[] InA,int InAPos,byte[] InB,int InBPos,int Plen)
	{
		for(int i = 0; i < Plen; i ++)
			InA[InAPos + i] ^= InB[InBPos + i];
	}
	void RotateL(byte[] Pin,int Pstart,int Plen,int loop)
	{
		System.arraycopy( Pin, Pstart,Tmp, 0, loop);
		System.arraycopy( Pin, Pstart + loop,Pin, Pstart, Plen - loop);
		System.arraycopy( Tmp, 0,Pin, Pstart + Plen - loop, loop);
	}
	void ByteToBit(byte[] Pout,int outPos,byte[] Pin,int inPos,int bits)
	{
		for(int i = 0; i < bits; i ++)
			Pout[outPos + i] = (byte) ((Pin[inPos + (i >> 3)] >> (i&7)) & 0x01);
	}
	void BitToByte(byte[] Pout,int outPos,byte[] Pin,int PinPos,int bits)
	{
		Pout.clone();
		for(int i = 0; i < bits; i ++)
			Pout[outPos + i >> 3] |= Pin[PinPos + i] << (i&7);
	}
}
